/*
 * Copyright 2016-2022 dromara.org.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.dromara.mendmix.gateway.component.rewrite;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;
import org.dromara.mendmix.common.http.HttpRequestEntity;
import org.dromara.mendmix.common.model.IdNamePair;
import org.dromara.mendmix.common.model.ValueParam;
import org.dromara.mendmix.common.util.DigestUtils;
import org.dromara.mendmix.common.util.JsonUtils;
import org.dromara.mendmix.common.util.StringConverter;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
 * 
 * @description <br>
 * @author <a href="mailto:vakinge@gmail.com">jiangwei</a>
 * @date 2020年5月12日
 */
public class RewriteExecutor {
	
	public static String doRewrite(RewriteRule rule,String content) {
		boolean replaceMode;
		if((replaceMode = rule.getRuleType() == RewriteRuleType.mapping) || rule.getRuleType() == RewriteRuleType.filter) {
			Map<String, Object> mapping = JsonUtils.toHashMap(rule.getRuleContent());
			JsonNode node = JsonUtils.toJsonNode(content);
			handleFieldValue(null,null,node, mapping, replaceMode);
			return node.toString();
		}else if(rule.getRuleType() == RewriteRuleType.custom) {
			HttpRequestEntity requestEntity = HttpRequestEntity.post(rule.getRuleContent());
			requestEntity.objectBody(new ValueParam(content));
			return requestEntity.useContext().execute().toObject(ValueParam.class).getValue();
		}
		return null;
	}

	/**
	 * 
	 * @param fieldName
	 * @param node
	 * @param valueMapping
	 * @param replaceMode  替换模式 /过滤模式
	 */
	private static FilterStragery handleFieldValue(JsonNode parentNode,String fieldName,JsonNode node, Map<String, Object> valueMapping, boolean replaceMode) {
		//<field,<value,mappingValue>>
		//<field,FilterStragery>
		if(node.isObject()) {
			Iterator<Entry<String, JsonNode>> iterator = node.fields();
			List<String> removeFields = new ArrayList<>();
			while(iterator.hasNext()) {
				Entry<String, JsonNode> entry = iterator.next();
				String key = entry.getKey();
	            JsonNode valueNode = entry.getValue();
	            FilterStragery filterStragery = handleFieldValue(node,key,valueNode, valueMapping, replaceMode);
			    if(FilterStragery.remove == filterStragery) {
			    	removeFields.add(key);
			    }
			}
			if(!removeFields.isEmpty()) {
				((ObjectNode)node).remove(removeFields);
			}
	    }else if(node.isArray()) {
	        node.elements().forEachRemaining(subNode -> {
	        	handleFieldValue(null,null,subNode, valueMapping, replaceMode);
	        });
	    }else{
	    	if(parentNode != null && fieldName != null && valueMapping.containsKey(fieldName)) {
	    		String originValue = node.asText();
	    		if(StringUtils.isBlank(originValue)) {
	    			return null;
	    		}
	    		String newValue = null;
	    		if(replaceMode) {
	    			newValue = ((Map<String, String>)valueMapping.get(fieldName)).get(originValue);
	    		}else {
	    			String stragery = valueMapping.get(fieldName).toString();
	    			if(FilterStragery.masking.name().equals(stragery)) {
	    				newValue = StringConverter.getDesensitizedValue(originValue);
	    			}else if(FilterStragery.remove.name().equals(stragery)) {
	    				return FilterStragery.remove;
	    			}else if(FilterStragery.confuse.name().equals(stragery)) {
	    				newValue = DigestUtils.md5Short(originValue);
	    			}
	    		}
	    		if(newValue != null) {
	    			((ObjectNode)parentNode).put(fieldName, newValue);
	    		}
	    	}
	    }
		
		return null;
		
	}
	
	public static void main(String[] args) {
		Map<String, Object>  map = new HashMap<>();
		map.put("id", "xyz123");
		map.put("name", "xyz123");
		map.put("num", 1);
		map.put("object", new IdNamePair("1", "aa123"));
		map.put("list", Arrays.asList(new IdNamePair("1", "aa456")));
		
		JsonNode jsonNode = JsonUtils.toJsonNode(JsonUtils.toJson(map));
		Map<String, Object> valueMapping = new HashMap<>();
		valueMapping.put("name", "masking");
		valueMapping.put("id", "remove");
		handleFieldValue(null,null,jsonNode, valueMapping, false);
		
		System.out.println(jsonNode.toPrettyString());
	}

}
